<cfcomponent name="HibernateFactory" hint="Factory for getting to Hibernate objects">

<cfscript>
	instance = StructNew();
</cfscript>

<cffunction name="dumpvar">
  <cfargument name="var" default="blank">
  <cfargument name="abort" default="true">
  <cftry>
	  <cfdump var="#var#">
	<cfcatch>
	  <cfset writeoutput(cfcatch.Message & " " & cfcatch.Detail & " " & cfcatch.TagContext[1].line & " " & cfcatch.stacktrace) />
	</cfcatch>
	</cftry>
	<cfif arguments.abort>
	  <cfabort />
	</cfif>
</cffunction>

<cffunction name="newJavaObject" output="false">
  <cfargument name="class">
	<cfreturn createObject("java", arguments.class) />
</cffunction>

	<cffunction name="translateCfSqlType" hint="I translate the MySQL data type names into ColdFusion cf_sql_xyz names" output="false" returntype="string">
		<cfargument name="typeName" hint="I am the type name to translate" required="yes" type="string" />
		
		<cfswitch expression="#arguments.typeName#">
			<cfcase value="bigint">
				<cfreturn "cf_sql_bigint" />
			</cfcase>
			<cfcase value="binary">
				<cfreturn "cf_sql_binary" />
			</cfcase>
			<cfcase value="bit">
				<cfreturn "cf_sql_bit" />
			</cfcase>
			<cfcase value="char">
				<cfreturn "cf_sql_char" />
			</cfcase>
			<cfcase value="datetime">
				<cfreturn "cf_sql_timestamp" />
			</cfcase>
			<cfcase value="decimal">
				<cfreturn "cf_sql_decimal" />
			</cfcase>
			<cfcase value="double">
				<cfreturn "cf_sql_numeric" />
			</cfcase>
			<cfcase value="float">
				<cfreturn "cf_sql_float" />
			</cfcase>
			<cfcase value="image">
				<cfreturn "cf_sql_longvarbinary" />
			</cfcase>
			<cfcase value="int">
				<cfreturn "cf_sql_integer" />
			</cfcase>
			<cfcase value="money">
				<cfreturn "cf_sql_money" />
			</cfcase>
			<cfcase value="nchar">
				<cfreturn "cf_sql_char" />
			</cfcase>
			<cfcase value="ntext">
				<cfreturn "cf_sql_longvarchar" />
			</cfcase>
			<cfcase value="numeric">
				<cfreturn "cf_sql_varchar" />
			</cfcase>
			<cfcase value="nvarchar">
				<cfreturn "cf_sql_varchar" />
			</cfcase>
			<cfcase value="longtext">
				<cfreturn "cf_sql_longvarchar" />
			</cfcase>
			<cfcase value="real">
				<cfreturn "cf_sql_real" />
			</cfcase>
			<cfcase value="smalldatetime">
				<cfreturn "cf_sql_date" />
			</cfcase>
			<cfcase value="smallint">
				<cfreturn "cf_sql_smallint" />
			</cfcase>
			<cfcase value="smallmoney">
				<cfreturn "cf_sql_decimal" />
			</cfcase>
			<cfcase value="text">
				<cfreturn "cf_sql_longvarchar" />
			</cfcase>
			<cfcase value="timestamp">
				<cfreturn "cf_sql_timestamp" />
			</cfcase>
			<cfcase value="tinyint">
				<cfreturn "cf_sql_tinyint" />
			</cfcase>
			<cfcase value="uniqueidentifier">
				<cfreturn "cf_sql_idstamp" />
			</cfcase>
			<cfcase value="varbinary">
				<cfreturn "cf_sql_varbinary" />
			</cfcase>
			<cfcase value="varchar">
				<cfreturn "cf_sql_varchar" />
			</cfcase>
		</cfswitch>
	</cffunction>

	<cffunction name="translateDataType" hint="I translate the MSSQL data type names into ColdFusion data type names" output="false" returntype="string">
		<cfargument name="typeName" hint="I am the type name to translate" required="yes" type="string" />

		<cfswitch expression="#arguments.typeName#">
			<cfcase value="bigint">
				<cfreturn "numeric" />
			</cfcase>
			<cfcase value="binary">
				<cfreturn "string" />
			</cfcase>
			<cfcase value="bit">
				<cfreturn "boolean" />
			</cfcase>
			<cfcase value="char">
				<cfreturn "string" />
			</cfcase>
			<cfcase value="datetime">
				<cfreturn "date" />
			</cfcase>
			<cfcase value="decimal">
				<cfreturn "numeric" />
			</cfcase>
			<cfcase value="double">
				<cfreturn "numeric" />
			</cfcase>
			<cfcase value="float">
				<cfreturn "numeric" />
			</cfcase>
			<cfcase value="image">
				<cfreturn "numeric" />
			</cfcase>
			<cfcase value="int">
				<cfreturn "numeric" />
			</cfcase>
			<cfcase value="integer">
				<cfreturn "numeric" />
			</cfcase>
			<cfcase value="money">
				<cfreturn "numeric" />
			</cfcase>
			<cfcase value="nchar">
				<cfreturn "string" />
			</cfcase>
			<cfcase value="ntext">
				<cfreturn "string" />
			</cfcase>
			<cfcase value="numeric">
				<cfreturn "numeric" />
			</cfcase>
			<cfcase value="number">
				<cfreturn "numeric" />
			</cfcase>
			<cfcase value="nvarchar">
				<cfreturn "ntring" />
			</cfcase>
			<cfcase value="longtext">
				<cfreturn "string" />
			</cfcase>
			<cfcase value="string">
				<cfreturn "string" />
			</cfcase>
			<cfcase value="real">
				<cfreturn "numeric" />
			</cfcase>
			<cfcase value="long">
				<cfreturn "numeric" />
			</cfcase>
			<cfcase value="smalldatetime">
				<cfreturn "date" />
			</cfcase>
			<cfcase value="smallint">
				<cfreturn "numeric" />
			</cfcase>
			<cfcase value="smallmoney">
				<cfreturn "numeric" />
			</cfcase>
			<cfcase value="text">
				<cfreturn "string" />
			</cfcase>
			<cfcase value="timestamp">
				<cfreturn "date" />
			</cfcase>
			<cfcase value="tinyint">
				<cfreturn "boolean" />
			</cfcase>
			<cfcase value="uniqueidentifier">
				<cfreturn "string" />
			</cfcase>
			<cfcase value="varbinary">
				<cfreturn "string" />
			</cfcase>
			<cfcase value="varchar">
				<cfreturn "string" />
			</cfcase>
		</cfswitch>
		<cfreturn typeName>
	</cffunction>
<!------------------------------------------- PUBLIC ------------------------------------------->

<cffunction name="init" hint="Constructor: takes directory to export to" access="public" returntype="EntityGenerator" output="false">
	<cfargument name="exportDirectory">	
	<cfargument name="entitiesMetaData">	
	<cfscript>
	 	instance.exportDirectory = arguments.exportDirectory;
	 	instance.entitiesMetaData = arguments.entitiesMetaData;
	 	return this;
	</cfscript>
</cffunction>

<cffunction name="generate" hint="Constructor: takes directory to export to" access="public" returntype="any" output="false">
	<cfargument name="entities" default="">	
	<cfscript>
	 	var entitiesMetaData = instance.entitiesMetaData;
	 	if(arguments.entities eq "") {
	 	  entityList = structKeyList(entitiesMetaData);
	 	  for(x = 1; x lte listLen(entityList); x = x+1) {
	 	  	entityName = listGetAt(entityList,x);
	 	  	generateEntity(entityName);
	 	  }
	 	}
	</cfscript>
</cffunction>

<cffunction name="generateEntity" hint="Constructor: takes directory to export to" access="public" returntype="any" output="false">
	<cfargument name="entityName" required="true" />	
	<cfscript>
	 	var entityXML = getEntityXML(entityName);
	 	var entityCFC = "";
	 	var exportPath = instance.exportDirectory & "/" & replace(listDeleteAt(entityName,listLen(entityName,"."),"."),".","/","all");
	 	var beanFilePath = exportPath & "/" & listLast(entityName,".") & ".cfc";
	 	var toFilePath = exportPath & "/" & listLast(entityName,".") & "TO.cfc";
	</cfscript>
	<cftry>
		<cfdirectory action="create" directory="#exportPath#" />
		<cfcatch>
			directory exists or not permissions, we continues...
		</cfcatch>
	</cftry>
	<cffile action="read" file="#expandpath("./hibernate/xsl/hashmap.xsl")#" variable="template">
	<cfset entityCFC = xmlTransform(entityXML,template) />
	<cffile action="write" file="#toFilePath#" output="#entityCFC#">
	<cffile action="read" file="#expandpath("./hibernate/xsl/bean/bean.xsl")#" variable="template">
	<cfset entityCFC = xmlTransform(entityXML,template) />
	<cffile action="write" file="#beanFilePath#" output="#entityCFC#">
</cffunction>

	<cffunction name="getEntityXML" access="public" output="false" returntype="xml">
		<cfargument name="entityName" default="">	
		<cfscript>
		 	var entitiesMetaData = instance.entitiesMetaData;
	  	var entity = entitiesMetaData[entityName];
	  	var entityProps = entity["properties"];
	  	var KeyColumnNames = arrayToList(entity["KeyColumnNames"]);
	  	var entityPropNames = structKeyList(entityProps);
			var xmlTable = "";
		</cfscript>
		<!--- convert the table data into an xml format --->
		<cfxml variable="xmlTable">
		<cfoutput>
		<root>
			<bean name="#arguments.entityName#" path="#listLast(arguments.entityName,".")#">
				<dbtable name="#arguments.entityName#" type="hibername">
				<cfloop list="#entityPropNames#" index="prop">
					<cfset property = entityProps[prop] />
					<cfset column = property["column"] />
					<cfset columnName = column["Name"] />
					<cfset datatype = entityProps[prop]["type"].getName() />
					<column name="#prop#"
							type="#translateDataType(dataType)#"
							cfSqlType="#translateCfSqlType(datatype)#"
							required="#column["Nullable"]#"
							columnType="#column["Value"].getTypeName()#"
							hibernateClass="#property["hibernateClass"]#"
							length="#column["Length"]#"
							primaryKey="#yesNoFormat(listFind(keyColumnNames,columnName))#"
							identity="#column["Unique"]#" />
				</cfloop>
				</dbtable>
			</bean>
		</root>
		</cfoutput>
		</cfxml>
		<cfreturn xmlTable />
	</cffunction>


</cfcomponent>
